﻿using System;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace Comm.Security
{
    /// <summary>
    /// 客户端许可操作
    /// </summary>
    public class ClientLicense
    {
        /// <summary>
        /// 许可文件
        /// </summary>
        const string CONST_LINCENSE_FILENAME = "Clicense.dat";

        private readonly XDocument xDoc;

        /// <summary>
        /// 检查是否授权
        /// </summary>
        /// <param name="sn">需要查询的硬盘序列号，多个硬盘序列号，使用逗号分隔传入</param>
        /// <returns></returns>
        public bool IsAuthorized(string sn)
        {
            string[] tmparr = sn.Split(',');

            string s = xDoc.Descendants("Item").First(xe => xe.Attribute("Name").Value == "Sn").Attribute("Value").Value;

            var isFind = tmparr.Any(tmp => s == tmp.Trim());

            if (!isFind) return false;

            int count = int.Parse(xDoc.Descendants("Item").First(xe => xe.Attribute("Name").Value == "Count").Attribute("Value").Value);

            if (count == -1) return true;

            if (count == 0) return false;

            DateTime lastLoginTime = DateTime.Now;

            try
            {
                //如果最后一次登录，是今天，则直接返回true
                lastLoginTime = DateTime.Parse(xDoc.Descendants("Item").First(xe => xe.Attribute("Name").Value == "LoginDate").Attribute("Value").Value);
            }
            catch
            {
                try
                {
// ReSharper disable PossibleNullReferenceException
                    xDoc.Element("License").Add(new XElement("Item", new XAttribute("Name", "LoginDate"), new XAttribute("Value", DateTime.Now)));
// ReSharper restore PossibleNullReferenceException
                }
                catch { return false; }
            }

            //系统时间不对
            if (DateTime.Now < lastLoginTime)
            {
                return false;
            }
            xDoc.Descendants("Item").First(xe => xe.Attribute("Name").Value == "LoginDate").Attribute("Value").Value = DateTime.Now.ToString(CultureInfo.InvariantCulture);

            var daysCount =Math.Abs( lastLoginTime.Subtract(DateTime.Now).Days);

            if (daysCount  != 0)
            {
                count -= daysCount;
                if (count < 0) count = 0;
                xDoc.Descendants("Item").First(xe => xe.Attribute("Name").Value == "Count").Attribute("Value").Value = count.ToString(CultureInfo.InvariantCulture);
            }
            Save(xDoc);

            return count>0;
        }


        /// <summary>
        /// 不允许外部创建实例
        /// </summary>
        private ClientLicense(XDocument xdoc)
        {
            xDoc = xdoc;
        }

        /// <summary>
        /// 创建一个许可文件
        /// </summary>
        /// <param name="DayCount">许可天数，-1为无限制</param>
        /// <param name="FilePrescription">文件时效</param>
        /// <param name="DiskSn">磁盘序列号，多磁盘任意选择一个</param>
        /// <param name="CallBackMethod"></param>
        /// <returns></returns>
        public static bool Create(int DayCount, int FilePrescription, string DiskSn, Action<byte[]> CallBackMethod = null)
        {
            var xDoc = new XDocument();

            xDoc.Add(new XElement("License",
                                  new XElement("Item",
                                                new XAttribute("Name", "Count"),                //授权许可天数
                                                new XAttribute("Value", DayCount)
                                               ),
                                  new XElement("Item",
                                                new XAttribute("Name", "Sn"),                    //授权磁盘序列号
                                                new XAttribute("Value", DiskSn)
                                               ),
                                  new XElement("Item",
                                                new XAttribute("Name", "LicenseDate"),           //授权日期，用于授权文件时效性检查
                                                new XAttribute("Value", DateTime.Now)
                                               ),
                                  new XElement("Item",
                                                new XAttribute("Name", "Prescription"),          //授权文件时效
                                                new XAttribute("Value", FilePrescription)
                                               )
                                   )
                     );

            if (CallBackMethod != null)
            {
                byte[] buffer = Encoding.UTF8.GetBytes(xDoc.ToString());

                buffer = Crypt.SchemeCrypt.Instance.Encrypt(buffer);

                CallBackMethod(buffer);

                return true;
            }

            Save(xDoc);
            return true;

        }

        /// <summary>
        /// 加载许可文件,如果成功，返回许可对象实例，如果失败则返回NULL
        /// </summary>
        /// <returns></returns>
        public static ClientLicense Load()
        {
            string path = string.Format(@"{0}\{1}", Environment.CurrentDirectory, CONST_LINCENSE_FILENAME);

            if (!System.IO.File.Exists(path))
            {
                return null;
            }

            try
            {
                byte[] buff;
                using (var fs = new System.IO.FileStream(path, System.IO.FileMode.Open, System.IO.FileAccess.Read))
                {
                    buff = new byte[fs.Length];

                    fs.Read(buff, 0, buff.Length);

                    fs.Close();
                }

                buff = Crypt.SchemeCrypt.Instance.Decrypt(buff);

                string xml = Encoding.UTF8.GetString(buff);

                XDocument xDoc = XDocument.Parse(xml);

                if (xDoc.Descendants("Item").Count(xe => xe.Attribute("Name").Value == "Count") != 1) return null;

// ReSharper disable ReturnValueOfPureMethodIsNotUsed
                int.Parse(xDoc.Descendants("Item").First(xe => xe.Attribute("Name").Value == "Count").Attribute("Value").Value);
// ReSharper restore ReturnValueOfPureMethodIsNotUsed

                int intPres = int.Parse(xDoc.Descendants("Item").First(xe => xe.Attribute("Name").Value == "Prescription").Attribute("Value").Value);

                if (intPres != -1)          //如果授权时效不等于-1，那么表示存在时效，需要比较许可生成时间，和当前PC时间，如果超过授权时效，则返回NULL
                {
                    DateTime dt = DateTime.Parse(xDoc.Descendants("Item").First(xe => xe.Attribute("Name").Value == "LicenseDate").Attribute("Value").Value);
                    if (DateTime.Now.Subtract(dt).Days >= intPres) return null;

                    xDoc.Descendants("Item").First(xe => xe.Attribute("Name").Value == "Prescription").Attribute("Value").Value = "-1";           //修改授权时效

                    Save(xDoc);
                }

                return new ClientLicense(xDoc);

            }
            catch { return null; }

        }
        /// <summary>
        /// 加密存储
        /// </summary>
        /// <param name="xDoc"></param>
        private static void Save(XDocument xDoc)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(xDoc.ToString());

            buffer = Crypt.SchemeCrypt.Instance.Encrypt(buffer);

            string path = string.Format(@"{0}\{1}", Environment.CurrentDirectory, CONST_LINCENSE_FILENAME);

            using (var fs = new System.IO.FileStream(path, System.IO.FileMode.Create, System.IO.FileAccess.Write))
            {
                fs.Write(buffer, 0, buffer.Length);

                fs.Close();
            }
        }
    }
}
